package com.promis.okhttp;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;

import com.google.gson.reflect.TypeToken;
import com.promis.util.JsonUtils;
import com.promis.util.NetworkUtils;
import com.promis.util.ReflectUtils;
import com.promis.util.StringUtils;

import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by jidanbo on 2018/1/24.
 */

public abstract class HttpClient<T> {

    protected static final int SUCCESS_MESSAGE = 0;
    protected static final int FAILURE_MESSAGE = 1;

    private Context context;
    private static OkHttpClient client = null;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
//            super.handleMessage(msg);
            switch (msg.what) {
                case SUCCESS_MESSAGE:
                    handleResponse((String) msg.obj);
                    break;
                case FAILURE_MESSAGE:
                    handleFailure((String) msg.obj);
                    break;
            }
        }
    };

    public HttpClient(Context context) {
        this.context = context;

        if (client == null) {
            client = new OkHttpClient.Builder()
                    .cookieJar(new CookieJar() {
                        private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

                        @Override
                        public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
                            cookieStore.put(httpUrl.url().getHost(), list);
                        }

                        @Override
                        public List<Cookie> loadForRequest(HttpUrl httpUrl) {
                            List<Cookie> cookies = cookieStore.get(httpUrl.url().getHost());
                            return cookies != null ? cookies : new ArrayList<Cookie>();
                        }
                    })
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    .build();
        }
    }

    public void postAsyn(String url, HttpStringParams params) {
        RequestBody requestBody = getRequestBody(params);
        enqueue(newRequestBuilder(url).addHeader("ParamType", "form").post(requestBody).build());
    }

    public void postAsyn(String url, HttpJsonParams params) {
        RequestBody requestBody = getRequestBody(params);
        enqueue(newRequestBuilder(url).addHeader("ParamType", "json").post(requestBody).build());
    }

    public void postAsyn(String url, HttpFileParams params) {
        RequestBody requestBody = getRequestBody(params);
        enqueue(newRequestBuilder(url).addHeader("ParamType", "form").post(requestBody).build());
    }

//    public void post(String url, HttpFileParams params) {
//        RequestBody requestBody = getRequestBody(params);
//        execute(newRequestBuilder(url).post(requestBody).build());
//    }

    public void getAsyn(String url) {
        enqueue(newRequestBuilder(url).get().build());
    }

    private void enqueue(Request request) {
        if (NetworkUtils.isNetworkConnected(context)) {
            client.newCall(request).enqueue(newCallback());
        } else {
            onNetworkDisconnect();
        }
    }

    private Request.Builder newRequestBuilder(String url) {
        return new Request.Builder().url(url).addHeader("X-Client-Type", "Android").addHeader("AcceptType", "json");
    }

    private RequestBody getRequestBody(HttpFileParams params) {
        return params.getBuilder().build();
    }

    private RequestBody getRequestBody(HttpStringParams params) {
        return params.getBuilder().build();
    }

    private RequestBody getRequestBody(HttpJsonParams params) {
        HttpStringParams httpParams = new HttpStringParams();
        httpParams.add("params", params.getJsonParams());
        return httpParams.getBuilder().build();
    }

    private Callback newCallback() {
        return new Callback() {

            @Override
            public void onFailure(Call call, final IOException e) {
                handler.sendMessage(handler.obtainMessage(FAILURE_MESSAGE, "连接异常，请稍后重试!"));
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if (response.isSuccessful()) {
                    handler.sendMessage(handler.obtainMessage(SUCCESS_MESSAGE, response.body().string()));
                } else {
                    handler.sendMessage(handler.obtainMessage(FAILURE_MESSAGE, "响应异常：" + response.code() + "," + response.message()));
                }
            }
        };
    }

    private void handleResponse(String responseBody) {
        try {
//            Class<T> clz = ReflectUtils.getClassGenriceType(getClass());
//            T jsonResult = JsonUtils.fromJson(responseBody, clz);

            Type type = ReflectUtils.getSuperclassTypeParameter(getClass());
            T jsonResult = JsonUtils.fromJson(responseBody, type);
            if (JsonNormal.RESULT_LEVEL_SUCCESS.equals(((JsonNormal) jsonResult).getMsgLevel())) {
                onSuccess(jsonResult);
            } else if(((JsonNormal) jsonResult).isSessionInvaild()) {
                onSeesionInvaild();
            } else {
                onError(((JsonNormal) jsonResult).getMsgContent());
            }
        } catch (Exception ex) {
            //Toast.makeText(getContext(), ex.getMessage(), Toast.LENGTH_LONG).show();
            if (ex != null && !StringUtils.isNullOrEmpty(ex.getMessage())) {
                Log.e("Response Error: ", ex.getMessage());
            }
            onError("响应数据解析异常" + ex.getMessage());
        } finally {
            onFinish();
        }
    }

    private void handleFailure(String failureMessage) {
        onError(failureMessage);
        onFinish();
    }

    public Context getContext() {
        return context;
    }

    protected abstract void onSuccess(T result);

    protected void onError(String errorMsg) {}

    protected void onSeesionInvaild() {}

    protected void onFinish(){}

    protected void onNetworkDisconnect(){}
}
